home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Demos / Evatac Software / Preditor 3.0 / Tools / Language Module Builder / Sources / CParse.c < prev    next >
Text File  |  1996-02-08  |  28KB  |  1,322 lines

  1.  /************************************************************
  2.  
  3.     CParse.c
  4.     C Source to Preditor 3
  5.  
  6.     Language Module Code for the "C" and "C++" language
  7.  
  8.     © Copyright Evatac Software  1988-1996
  9.     All rights reserved
  10.  
  11. ************************************************************/
  12.  
  13. #include "CParse.h"
  14. #include <SetupA4.h>
  15. #include <MixedMode.h>
  16. #include <Ctype.h>
  17.  
  18. #ifndef THINKC
  19. #include <A4Stuff.h>
  20. #else
  21. #define SetCurrentA4()    0; RememberA4()
  22. #define SetA4(x)        SetUpA4()
  23. #endif
  24.  
  25. #ifdef powerc
  26. ProcInfoType __procinfo = LanguageUPPInfo;
  27. #endif
  28.  
  29. static languageGlobals            globals;
  30. static ExternalCallbackBlock    *callbacks;
  31. static languageToken            *funcTokPtr;
  32.  
  33. /*
  34.  * * * *     C LANGUAGE ELECTRIC HANDLER       * * * * * *
  35.  */
  36.  
  37. static long _languageConvertToTabs(
  38.     Char    *text,
  39.     long     length,
  40.     long    hardTab
  41.     )
  42. {
  43.     int        tabs   = length / hardTab;
  44.     int        spaces = length % hardTab;
  45.     int        newLen = tabs + spaces;
  46.  
  47.     while (tabs-- > 0)
  48.         *(text++) = 9;
  49.     while (spaces-- > 0)
  50.         *(text++) = ' ';
  51.  
  52.     return(newLen);
  53. }
  54.  
  55. /*
  56.  * _languageHandleElectric
  57.  *
  58.  * We get called only when there is no selection, and one of the
  59.  * 3 electrics is pressed [;{}].
  60.  */
  61. static void _languageHandleElectric(
  62.     Char        ch
  63.     )
  64. {
  65.     long        anchor, end, pos, length;
  66.     long        i;
  67.     long        lineNumber, leading;
  68.     short        spacesPerTab, hardTab;
  69.     Char        text[256], *ptr = text;
  70.     
  71.     extGetSelection(callbacks, &anchor, &end);
  72.  
  73.     lineNumber = extLineFromPosition(callbacks, anchor);
  74.     leading    = extGetLeading(callbacks, lineNumber, &length,
  75.                                 &spacesPerTab, &hardTab);
  76.     
  77.     pos           = anchor;
  78.     anchor        = extLineToPosition(callbacks, lineNumber);
  79.     
  80.     /*
  81.      * Get the indentation of the current line
  82.      */
  83.     
  84.     if (ch == ';') {
  85.                 
  86.         /*
  87.          * Don't expand if we are in the middle a for statement.  Doesn't
  88.          * catch if for is not first word in line, or the (;;) expression
  89.          * spans multiple lines
  90.          */
  91.         
  92.         length = 256 - 4;
  93.         
  94.         extGetText(callbacks, anchor, end, text, &length);
  95.         text[length]   = 0;
  96.         text[length+1] = 0;
  97.         
  98.         while (*ptr == ' ' || *ptr == '\t')
  99.             ptr++;
  100.         ptr[3] = 0;
  101.         
  102.         if (languageCStringCompare(ptr, (Char *) "for") == 0) {
  103.         
  104.             /* 
  105.              * Check to see if we are passed the ')'
  106.              */
  107.             
  108.             ptr += 4;
  109.             
  110.             while (*ptr != 0) {
  111.                 if (*ptr == ')') 
  112.                     break;
  113.                 ptr++;
  114.             }
  115.             
  116.             if (*ptr == 0) {
  117.                 extInsert(callbacks, (Char *) ";", 1);
  118.                 return;
  119.             }
  120.         }
  121.         
  122.         /*
  123.          * Now create the text to insert
  124.          */
  125.         
  126.         text[0] = ';';
  127.         text[1] = '\r';
  128.         
  129.         i = _languageConvertToTabs(text + 2, leading, hardTab); 
  130.         
  131.         extInsert(callbacks, text, i + 2);
  132.     }
  133.     
  134.     else if (ch == '}') {
  135.         
  136.         Int32    x;
  137.         Boolean    sameLine;
  138.         
  139.         /*
  140.          * See if we are on a blank line.  If we are, put the '}' on it,
  141.          * otherwise, insert on a new line
  142.          */
  143.         
  144.         x = extLineEnd(callbacks, lineNumber);
  145.         sameLine = (x - anchor == length);
  146.                     
  147.         text[0] = '}';
  148.         text[1] = 0;
  149.         
  150.         if ((x = extFindMatch(callbacks, text, end)) == -1) {
  151.             extInsert(callbacks, (Char *) "}", 1);
  152.             return;
  153.         }
  154.         
  155.         lineNumber = extLineFromPosition(callbacks, x);
  156.         leading    = extGetLeading(callbacks, lineNumber, &length,
  157.                                     &spacesPerTab, &hardTab);
  158.         
  159.         /*
  160.          * Now create the text to insert
  161.          */
  162.         
  163.         if (sameLine) {
  164.             extSetSelection(callbacks, anchor, pos);
  165.             x = 0;
  166.         }
  167.         else {
  168.             text[0] = '\r';
  169.             x = 1;
  170.         }
  171.         
  172.         i = _languageConvertToTabs(text + x, leading, hardTab); 
  173.         
  174.         text[i+x] = '}';
  175.         
  176.         extInsert(callbacks, text, i + x + 1);
  177.     }
  178.     
  179.     else if (ch == '{') {
  180.     
  181.         /*
  182.          * Create the text to insert
  183.          */
  184.         
  185.         text[0] = '{';
  186.         text[1] = '\r';
  187.         
  188.         i = _languageConvertToTabs(text + 2, leading + spacesPerTab, hardTab); 
  189.         
  190.         extInsert(callbacks, text, i + 2);
  191.     }
  192. }
  193.  
  194. /*
  195.  * * * *     C LANGUAGE INDENTING HANDLER       * * * * * *
  196.  */
  197.  
  198. /*
  199.  * _languageHandleIndent
  200.  *
  201.  * Indent the selected lines according to the buffer indentation settings
  202.  */
  203. static void _languageHandleIndent(
  204.     void        *extData
  205.     )
  206. {
  207.     long        anchor, end, pos, length;
  208.     long        lineStart;
  209.     long        i, x, newPos = -1;
  210.     long        lineNumber, endLineNumber, leading;
  211.     short        spacesPerTab, hardTab;
  212.     Char        text[256], ch;
  213.     
  214.     extGetSelection(callbacks, &anchor, &end);
  215.  
  216.     if (anchor > end) {
  217.         pos = anchor; anchor = end; end = pos;   /* Swap */
  218.     }
  219.     
  220.     lineNumber    = extLineFromPosition(callbacks, anchor);
  221.     endLineNumber = extLineFromPosition(callbacks, end);
  222.  
  223.     /*
  224.      * Indent each line in the selection
  225.      */
  226.      
  227.     while (lineNumber <= endLineNumber) {
  228.         
  229.         if (lineNumber <= 1) {
  230.             lineNumber++;
  231.             continue;
  232.         }
  233.         
  234.         leading  = extGetLeading(callbacks, lineNumber, &length,
  235.                                    &spacesPerTab, &hardTab);
  236.     
  237.         lineStart = extLineToPosition(callbacks, lineNumber);
  238.         
  239.         /*
  240.          * Select the leading spaces/tabs
  241.          */
  242.          
  243.         extSetSelection(callbacks, lineStart, lineStart + length);
  244.  
  245.         /*
  246.          * Scan back previous lines for a line that we can relate to
  247.          */
  248.  
  249.         x = 1;
  250.  
  251.         for (;;) {
  252.  
  253.             if (lineNumber - x < 1)
  254.                 break;
  255.  
  256.             leading  = extGetLeading(callbacks, lineNumber - x, &length,
  257.                                        &spacesPerTab, &hardTab);
  258.                                        
  259.             end      = extLineEnd(callbacks, lineNumber - x);
  260.             pos         = extLineToPosition(callbacks, lineNumber - x);
  261.             
  262.             /* Skip Blank lines */
  263.  
  264.             if (length == (end - pos)) {
  265.                 x++;
  266.                 continue;
  267.                }
  268.             
  269.             i = pos + length;
  270.             
  271.             /*
  272.              * Indent right if line contains a left bracket
  273.              */
  274.             
  275.             extScanContents(callbacks, i);
  276.             
  277.             while (i++ < end && extNextScanCharacter(callbacks, &ch)) {
  278.                 
  279.                 if (ch == '{') {
  280.                     leading += spacesPerTab;
  281.                     break;
  282.                 }
  283.             }
  284.             
  285.             extDoneScan(callbacks);
  286.  
  287.         
  288.             /*
  289.               * Indent the line
  290.              */
  291.             
  292.             i = _languageConvertToTabs(text, leading, hardTab); 
  293.         
  294.             extInsert(callbacks, text, i);
  295.             
  296.             if (newPos == -1)
  297.                 newPos = lineStart + i;
  298.             break;
  299.         }
  300.         
  301.         lineNumber++;
  302.     }
  303.  
  304.     if (newPos >= 0)
  305.         extSetSelection(callbacks, newPos, newPos);
  306. }
  307.  
  308. /*
  309.  * * * *     C LANGUAGE PARSER       * * * * * *
  310.  */
  311.  
  312. /*
  313.  * _languageBuildString
  314.  *
  315.  * Build up a literal string or literal contant "foo" or 'foo'
  316.  */
  317. static void _languageBuildString(
  318.     languageToken            *token,
  319.     int                        c
  320.     )
  321. {
  322.     Int32    index = 1, size = kTokenStringSize;
  323.     int        origC = c;
  324.     
  325.     token->string[1]     = c;
  326.     token->type = (c == '\"' ? kSymbolStringLiteral : kSymbolCharConstant);
  327.     
  328.     if (c == 'l' || c == 'L') {
  329.         
  330.         c = languageGetChar(&globals, callbacks);
  331.         token->string[0] = c;
  332.         index = 2;
  333.     }
  334.     
  335.     while ((c = languageGetChar(&globals, callbacks)) != -1) {
  336.         
  337.         if (index < size)
  338.             token->string[++index] = c;
  339.         
  340.         if (c == origC)
  341.             break;
  342.         
  343.         else if (c == '\\') {
  344.         
  345.             c = languageGetChar(&globals, callbacks);
  346.             
  347.             if (c != -1) {
  348.                 
  349.                 if (index < size)
  350.                     token->string[++index] = c;
  351.             }
  352.         }
  353.     }
  354.     
  355.     token->string[0] = index;        /* So string can be used as C or Pascal string */
  356.     token->string[++index] = 0;
  357. }
  358.  
  359. /*
  360.  * _languageBuildWhiteSpace
  361.  *
  362.  * Build up a directive (i.e. #define, etc)
  363.  */
  364. static void _languageBuildWhiteSpace(
  365.     languageToken             *token,
  366.     int                     c
  367.     )
  368. {
  369.     token->type = kSymbolWhiteSpace;
  370.     
  371.     while ((c = languageGetChar(&globals, callbacks)) != -1) {
  372.         
  373.         if (c != ' ' && c != '\t' && c != '\v' && c != '\n' &&
  374.             c != '\r' && c != '\f' && c != '\b') {
  375.     //    if (!isspace(c)) {
  376.             languageUngetChar(&globals, c);
  377.               return;
  378.         }
  379.     }
  380. }
  381.  
  382. /*
  383.  * _languageBuildComment
  384.  *
  385.  */
  386. static void _languageBuildComment(
  387.     languageToken             *token,
  388.     int                     c
  389.     )
  390. {
  391.     Boolean     wasStar;
  392.  
  393.     token->type                 = kSymbolComment;
  394.     globals.startLastComment     = globals.position;
  395.  
  396.     c = languageGetChar(&globals, callbacks);
  397.     
  398.     if (c =='*') {
  399.     
  400.         wasStar = false;
  401.  
  402.         while ((c = languageGetChar(&globals, callbacks)) != -1) {
  403.  
  404.             if (c == '*')
  405.                 wasStar = true;
  406.             else if (c != '/' || !wasStar)
  407.                 wasStar = false;
  408.              else
  409.                 break;
  410.         }
  411.     }
  412.  
  413.     else if (c == '/') {
  414.     
  415.         while ((c = languageGetChar(&globals, callbacks)) != -1) {
  416.  
  417.             if (c == 13)
  418.                 break;
  419.         }
  420.     }
  421. }
  422.  
  423. /*
  424.  * _languageBuildNumber
  425.  *
  426.  */
  427. static void _languageBuildNumber(
  428.     languageToken             *token,
  429.     int                     c
  430.     )
  431. {
  432.     token->type = kSymbolIntConstant;
  433.  
  434.     if (c == '0') {
  435.     
  436.         c = languageGetChar(&globals, callbacks);
  437.  
  438.         if (c == 'x' || c == 'X') {
  439.         
  440.             while ((c = languageGetChar(&globals, callbacks)) != -1) {
  441.  
  442.                 if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
  443.                     ;
  444.                 else
  445.                     break;
  446.             }
  447.         }
  448.    
  449.         else {
  450.         
  451.             while (c != -1) {
  452.     
  453.                 if (c >= '0' && c <= '7')
  454.                     ;
  455.                 else
  456.                     break;
  457.         
  458.                 c = languageGetChar(&globals, callbacks);
  459.             }
  460.         }
  461.     }
  462.     
  463.     else {                                    /* decimal */
  464.  
  465.         while ((c = languageGetChar(&globals, callbacks)) != -1) {
  466.  
  467.             if (c >= '0' && c <= '9') 
  468.                 ;
  469.             else
  470.                 break;
  471.         }
  472.  
  473.         if (c == '.') {
  474.             
  475.             token->type = kSymbolFloatConstant;
  476.  
  477.             while ((c = languageGetChar(&globals, callbacks)) != -1) {
  478.             
  479.                 if (c >= '0' && c <= '9')
  480.                     ;
  481.                  else
  482.                     break;
  483.             }
  484.         }
  485.  
  486.         if (c == 'e' || c == 'E') {
  487.         
  488.             token->type = kSymbolFloatConstant;
  489.  
  490.             c = languageGetChar(&globals, callbacks);
  491.  
  492.             if (c == '-' || c == '+')
  493.                 c = languageGetChar(&globals, callbacks);
  494.  
  495.             while (c != -1) {
  496.  
  497.                 if (c >= '0' && c <= '9')
  498.                     ;
  499.                 else
  500.                     break;
  501.  
  502.                 c = languageGetChar(&globals, callbacks);
  503.             }
  504.         }
  505.     }
  506.  
  507.     while (c != -1) {
  508.         
  509.         if (c == 'l' || c == 'L' || c == 'u' || c == 'U' ||
  510.             c == 'f' || c == 'F' || c == 'h' || c == 'H')    
  511.             ;
  512.         else
  513.             break;
  514.         
  515.         c = languageGetChar(&globals, callbacks);
  516.     }
  517.     
  518.     if (c != -1)
  519.         languageUngetChar(&globals, c);
  520. }
  521.  
  522. /*
  523.  * _languageBuildInclude
  524.  */
  525. static void _languageBuildInclude(
  526.     languageToken             *token,
  527.     int                     c
  528.     )
  529. {
  530.     Int32            index = 0, size = kTokenStringSize;
  531.     int                origC;
  532.     
  533.     languageUngetChar(&globals, c);
  534.     _languageBuildWhiteSpace(token, c);
  535.     
  536.     token->type = kSymbolInclude;
  537.     
  538.     if ((c = languageGetChar(&globals, callbacks)) == '\"' || c == '<') {
  539.         
  540.         origC = (c == '<' ? '>' : c);
  541.         
  542.         while ((c = languageGetChar(&globals, callbacks)) != -1) {
  543.         
  544.             if (c == origC)
  545.                 break;
  546.                 
  547.             if (index < size)
  548.                 token->string[++index] = c;
  549.         }
  550.     }
  551.  
  552.     token->string[0] = index;        /* So string can be used as C or Pascal string */
  553.     token->string[++index] = 0;
  554. }
  555.  
  556. /*
  557.  * _languageBuildWord
  558.  *
  559.  *
  560.  */
  561. static void _languageBuildWord(
  562.     languageToken             *token,
  563.     int                     c
  564.     )
  565. {
  566.     Int32            index = 1, size = kTokenStringSize;
  567.  
  568.     token->type = kSymbolIdentifier;
  569.  
  570.     token->string[1] = c;
  571.     
  572.     while ((c = languageGetChar(&globals, callbacks)) != -1) {
  573.  
  574.         if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_'
  575.             || c >= '0' && c <= '9') {
  576.         
  577.             if (index < size)
  578.                 token->string[++index] = c;
  579.         }
  580.         else {
  581.         
  582.             languageUngetChar(&globals, c);
  583.             break;
  584.         }
  585.     }
  586.  
  587.     token->string[0] = index;        /* So string can be used as C or Pascal string */
  588.     token->string[++index] = 0;
  589.  
  590.     /*
  591.      * Since hashing into a large reserved word table takes time, the reserved
  592.      * word table is not loaded for "function" scanning.  We do our own
  593.      * limited keyword check
  594.      */
  595.      
  596.     if (!languageHasTable(&globals)) {
  597.         
  598.         Char        *scan = token->string;
  599.         
  600.         if (scan[1] == 't' && scan[2] == 'y' && scan[3] == 'p' && scan[4] == 'e' &&
  601.             scan[5] == 'd' && scan[6] == 'e' && scan[7] == 'f')
  602.             token->type = kSymbolReservedWord;
  603.         else if (scan[1] == '#' && scan[2] == 'p' && scan[3] == 'r' && scan[4] == 'a' &&
  604.             scan[5] == 'g' && scan[6] == 'm' && scan[7] == 'a')
  605.             token->type = kSymbolReservedWord;
  606.         else if (scan[1] == 'm' && scan[2] == 'a' && scan[3] == 'r' && scan[4] == 'k')
  607.             token->type = kSymbolReservedWord;
  608.         else if (scan[1] == 'o' && scan[2] == 'p')
  609.             token->type = kSymbolReservedWord;
  610.  
  611.         return;
  612.     }
  613.     else if (languageTableLookup((&globals), token->string + 1)) 
  614.         token->type = kSymbolReservedWord; 
  615.     else if (languageCustomTableLookup((&globals), token->string + 1))
  616.         token->type = kSymbolCustomWord;
  617. }
  618.  
  619. /*
  620.  * _languageBuildDirective
  621.  *
  622.  * Build up a directive (i.e. #define, etc)
  623.  */
  624. static void _languageBuildDirective(
  625.     languageToken             *token,
  626.     int                     c
  627.     )
  628. {
  629.     int        prevCh = c;
  630.     
  631. //    _languageBuildWord(token, c);
  632.         
  633.     token->type                 = kSymbolPreprocessorDirective;
  634.     
  635.     while ((c = languageGetChar(&globals, callbacks)) != -1) {
  636.  
  637.         if (c == 13 && prevCh != '\\')
  638.             break;
  639.     
  640.         prevCh = c;
  641.     }
  642.     
  643. #if 0
  644.       Boolean    isInsideComment;
  645.     int     lastc;
  646.  
  647.     token->type = kSymbolPreprocessorDirective;
  648.  
  649.     lastc = 0;
  650.  
  651.     while ((c = languageGetChar(&globals, callbacks)) != -1) {
  652.  
  653.         if (c == '*' && lastc == '/')
  654.             isInsideComment = true;
  655.  
  656.         if (isInsideComment && c == '/' && lastc == '*') {
  657.             
  658.             isInsideComment = false;
  659.             lastc = ' ';
  660.         }
  661.         else
  662.             lastc = c;
  663.  
  664.         if (!isInsideComment && c == 13)
  665.             break;
  666.         else if (c == '\\') {
  667.             c = languageGetChar(&globals, callbacks);
  668.         }
  669.     }
  670. #endif
  671. }
  672.  
  673. /*
  674.  * _languageConcatPStrings
  675.  * 
  676.  * Concatenate two Pascal strings by attaching the second string on
  677.  * the end of the first    string.
  678.  */
  679. static void _languageConcatPStrings(
  680.     Char    *first,
  681.     Char    *second
  682.     )
  683. {
  684.     BlockMove(second + 1, first    + first[0] + 1,    (long) second[0]);
  685.     first[0] +=    second[0];
  686. }
  687.  
  688. /*
  689.  * _languageGetNextToken
  690.  */
  691. static languageToken *_languageGetNextToken(void)
  692. {
  693.     Int16                    previousType;
  694.     languageToken            *token = &globals.token;
  695.     int                     first, second;
  696.    
  697.     previousType            = token->type;
  698.     token->startLocation     = globals.position;
  699.     token->majorType        = -1;
  700.     
  701.     if ((first = languageGetChar(&globals, callbacks)) == -1)
  702.         return(nil);
  703.  
  704.     second = languagePeekChar(&globals, callbacks);
  705.     
  706.     token->type             = first;
  707.     token->string[1]     = first;
  708.     token->string[2]     = second;
  709.  
  710.     if (previousType == kSymbolReservedWord && 
  711.         token->string[1] == '#' && token->string[2] == 'i' && token->string[3] == 'n') {
  712.  
  713.         _languageBuildInclude(token, first);
  714.         first = 0;
  715.     }
  716.     
  717.     switch(first) {
  718.  
  719. /* "strings" */
  720. /* 'character constants' */
  721.  
  722.     case '\"':
  723.     case '\'':
  724.         _languageBuildString(token, first);
  725.         break;
  726.  
  727. /* preprocessor directive */
  728.  
  729.     case '#':
  730.         if (second != 'p') {
  731.             _languageBuildDirective(token, first);
  732.             globals.startLastComment = -1;
  733.         }
  734.         else
  735.                _languageBuildWord(token, first);
  736.         break;
  737.  
  738. /* white space */
  739.  
  740.     case '\n': case '\r':
  741.         funcTokPtr->type     = -1;
  742.     case ' ': case '\t': case '\v': case '\f': case '\b':
  743.         _languageBuildWhiteSpace(token, first);
  744.         break;
  745.  
  746. /* monographs */
  747.     case ';':
  748.         globals.startLastComment = -1;
  749.     case '(':
  750.     case ')':
  751.     case '[':
  752.     case ']':
  753.     case '{':
  754.     case '}':
  755.     case '\\':
  756.     case ',':
  757.       break;
  758.  
  759. /* / * can't nest comments * /   also does / and /= */
  760.  
  761.     case '/':
  762.         if (second == '*' || second == '/')
  763.             _languageBuildComment(token, first);
  764.         else if (second == '=') {
  765.             languageGetChar(&globals, callbacks);
  766.             token->type = kSymbolDivideAssign;
  767.         }
  768.         break;
  769.  
  770. /* *, *= */
  771.  
  772.     case '*':
  773.         if (second == '=') {
  774.             languageGetChar(&globals, callbacks);
  775.              token->type = kSymbolMultiplyAssign;
  776.          }
  777.      break;
  778.  
  779. /* %, %= */
  780.  
  781.     case '%':
  782.         if (second == '=') {
  783.             languageGetChar(&globals, callbacks);
  784.               token->type = kSymbolModAssign;
  785.         }
  786.         break;
  787.  
  788. /* !, != */
  789.  
  790.     case '!':
  791.            if (second == '=') {
  792.             languageGetChar(&globals, callbacks);
  793.               token->type = kSymbolNotEqual;
  794.         }
  795.         break;
  796.  
  797. /* &, &=, && */
  798.  
  799.     case '&':
  800.         if (second == '=') {
  801.             languageGetChar(&globals, callbacks);
  802.             token->type = kSymbolAndAssign;
  803.         }
  804.         else if (second == '&') {
  805.             languageGetChar(&globals, callbacks);
  806.             token->type = kSymbolAndAnd;
  807.         }
  808.         break;
  809.  
  810. /* |, ||, |= */
  811.  
  812.     case '|':
  813.         if (second == '=') {
  814.             languageGetChar(&globals, callbacks);
  815.             token->type = kSymbolOrAssign;
  816.         }
  817.            else if (second == '|') {
  818.             languageGetChar(&globals, callbacks);
  819.             token->type = kSymbolOrOr;
  820.         }
  821.     break;
  822.  
  823. /* +, ++, += */
  824.  
  825.     case '+':
  826.         if (second == '=') {
  827.             languageGetChar(&globals, callbacks);
  828.             token->type = kSymbolPlusAssign;
  829.         }
  830.         else if (second == '+') {
  831.             languageGetChar(&globals, callbacks);
  832.             token->type = kSymbolPlusPlus;
  833.         }
  834.         break;
  835.  
  836. /* -, --, -=, ->, ->* */
  837.  
  838.     case '-':
  839.         if (second == '=') {
  840.             languageGetChar(&globals, callbacks);
  841.             token->type = kSymbolMinusAssign;
  842.         }
  843.         else if (second == '-') {
  844.             languageGetChar(&globals, callbacks);
  845.             token->type = kSymbolMinusMinus;
  846.         }
  847.         else if (second == '>') {
  848.             languageGetChar(&globals, callbacks);
  849.             second = languagePeekChar(&globals, callbacks);
  850.  
  851.             if (second == '*') {
  852.                 languageGetChar(&globals, callbacks);
  853.                 token->type = kSymbolPointerStar;
  854.             }
  855.             else
  856.                 token->type = kSymbolPointer;
  857.         }
  858.         break;
  859.  
  860. /* ., .*, .NUM */
  861.  
  862.     case '.':
  863.         if (second == '*') {
  864.             languageGetChar(&globals, callbacks);
  865.             token->type = kSymbolDotStar;
  866.         }
  867.         
  868.         else if (second >= '0' && second <= '9')
  869.             _languageBuildNumber(token, first);
  870.             
  871.         else if (second == '.') {
  872.         
  873.             languageGetChar(&globals, callbacks);
  874.             
  875.             if (languagePeekChar(&globals, callbacks) == '.') {
  876.                 languageGetChar(&globals, callbacks);
  877.                 token->type = kSymbolEllipsis;
  878.              }
  879.              else {
  880.                  languageUngetChar(&globals, second);
  881.             }
  882.         }
  883.         break;
  884.  
  885. /* =, == */
  886.  
  887.     case '=':
  888.         if (second == '=') {
  889.             languageGetChar(&globals, callbacks);
  890.             token->type = kSymbolEqual;
  891.         }
  892.         break;
  893.  
  894. /* <, <<, <=, <<= */
  895.  
  896.     case '<':
  897.         if (second == '=') {
  898.             languageGetChar(&globals, callbacks);
  899.             token->type = kSymbolLessOrEqual;
  900.         }
  901.         else if (second == '<') {
  902.             languageGetChar(&globals, callbacks);
  903.             second = languagePeekChar(&globals, callbacks);
  904.  
  905.             if (second == '=') {
  906.                 languageGetChar(&globals, callbacks);
  907.                 token->type = kSymbolLeftShiftAssign;
  908.             }
  909.             else
  910.                 token->type = kSymbolLeftShift;
  911.         }
  912.         break;
  913.  
  914. /* >, >=, >>, >>= */
  915.  
  916.     case '>':
  917.         if (second == '=') {
  918.             languageGetChar(&globals, callbacks);
  919.             token->type = kSymbolGreaterOrEqual;
  920.         }
  921.         else if (second == '>') {
  922.             languageGetChar(&globals, callbacks);
  923.             second = languagePeekChar(&globals, callbacks);
  924.  
  925.             if (second == '=') {
  926.                 languageGetChar(&globals, callbacks);
  927.                 token->type = kSymbolRightShiftAssign;
  928.             }
  929.             else
  930.                 token->type = kSymbolRightShift;
  931.         }
  932.         break;
  933.  
  934. /* ^, ^= */
  935.  
  936.     case '^':
  937.       if (second == '=') {
  938.           languageGetChar(&globals, callbacks);
  939.           token->type = kSymbolXOrAssign;
  940.     }
  941.       break;
  942.  
  943. /* :, :: */
  944.  
  945.     case ':':
  946.         if (second == ':') {
  947.             languageGetChar(&globals, callbacks);
  948.               token->type = kSymbolScope;
  949.         }
  950.         break;
  951.  
  952. /* ?, ??=, ??/, ??', ??(, ??), ??! */
  953.  
  954.     case '?':
  955.         if (second == '?') {
  956.       
  957.               first  = languageGetChar(&globals, callbacks);
  958.               second = languageGetChar(&globals, callbacks);
  959.     
  960.             switch (second) {
  961.             
  962.             case '=':
  963.               token->type = kSymbolTrigraphPound;
  964.               break;
  965.             case '/':
  966.               token->type = kSymbolTrigraphBackSlash;
  967.               break;
  968.             case '\'':
  969.               token->type = kSymbolTrigraphXOr;
  970.               break;
  971.             case '(':
  972.               token->type = kSymbolTrigraphLeftHard;
  973.               break;
  974.             case ')':
  975.               token->type = kSymbolTrigraphRightHard;
  976.               break;
  977.             case '!':
  978.               token->type = kSymbolTrigraphBar;
  979.               break;
  980.             default:
  981.               token->type = kSymbolTrigraphUnknown;
  982.               break;
  983.             }
  984.         }
  985.         break;
  986.  
  987.     case 'l':
  988.     case 'L':
  989.         if (second == '\'' || second == '\"') {
  990.             _languageBuildString(token, first);
  991.             break;
  992.         }
  993.  
  994.       /* fall through */
  995.  
  996. /* the rest */
  997.  
  998.     default:
  999.         if (first >= '0' && first <= '9')
  1000.             _languageBuildNumber(token, first);
  1001.         else if (first >= 'a' && first <= 'z' || first >= 'A' && first <= 'Z' ||
  1002.                  first == '_' || first == '~')
  1003.                _languageBuildWord(token, first);
  1004.  
  1005.         /* Something weird, let the parser decide. */
  1006.  
  1007.         break;
  1008.     }
  1009.  
  1010.     token->endLocation    = globals.position;
  1011.     
  1012.     return(token);
  1013. }
  1014.  
  1015. void languageMain(
  1016.     ExternalCallbackBlock    *extCallbacks,
  1017.     WindowRef                window,
  1018.     long                    options,
  1019.     void                    *extData
  1020.     );
  1021.     
  1022. /*
  1023.  * languageMain
  1024.  *
  1025.  * This is the main entrypoint to the CODE module of a language module.
  1026.  * The following operations are defined:
  1027.  *
  1028.  *     kLanguageParse        Parse the source file, returning positions of all tokens
  1029.  *                        in the file.
  1030.  *  kLanguageFunctions    Parse the source file, returning the position of just the
  1031.  *                        functions in the source file
  1032.  *  kLanguageIncludes    Parse the source file, returning the #include files
  1033.  *  kLanguageTemplate    Expand macro -- insert template
  1034.  *  kLanguageIndent
  1035.  *    kLanguageElectric    Handle electric characters (i.e. }, {, ; )
  1036.  */
  1037.  
  1038. void main(
  1039.     ExternalCallbackBlock    *extCallbacks,
  1040.     WindowRef                window,
  1041.     long                    options,
  1042.     void                    *extData
  1043.     )
  1044. {
  1045.     int                    c;
  1046.     languageToken        *nextToken = nil, *token, tempToken;
  1047.     languageToken        saveToken, functionToken;
  1048.     Int16                bracketLevel = 0, functionLevel = -1;
  1049.     Int16                type, typedefLevel = -100;
  1050.     Int32                typedefStart;
  1051.     Boolean                hadSemicolon;
  1052.     long                 saved_a4;
  1053.  
  1054.     saved_a4   = SetCurrentA4();
  1055.     funcTokPtr = &functionToken;
  1056.  
  1057.     languageInit(&globals, extCallbacks, options);
  1058.  
  1059.     callbacks    = extCallbacks;
  1060.  
  1061.     if (options == kLanguageTemplate) {
  1062.  
  1063.         languageDefaultHandler(&globals, callbacks, options, extData);
  1064.     } 
  1065.     
  1066.     else if (options == kLanguageElectric) {
  1067.         
  1068.         _languageHandleElectric((Char) extData);
  1069.     }
  1070.     
  1071.     else if (options == kLanguageIndent) {
  1072.         
  1073.         _languageHandleIndent(extData);
  1074.     }
  1075.     
  1076.     else if (options <= kLanguageIncludes) {
  1077.         
  1078.         /*
  1079.          * Now parse the file, returning a series of valid return token types:
  1080.          *
  1081.          *        kFunction
  1082.          *         kKeyword
  1083.          *         kComment
  1084.          *        kCustomKeyword
  1085.          *         kDisabledText
  1086.          */
  1087.         
  1088.         functionToken.type        = -1;
  1089.     
  1090.         while (nextToken != nil || (token = _languageGetNextToken()) != nil) {
  1091.     
  1092.             if (nextToken != nil) {
  1093.                 token         = nextToken;
  1094.                 nextToken    = nil;
  1095.             }
  1096.       
  1097.             type = token->type;
  1098.             
  1099.             if (type == kSymbolReservedWord) {
  1100.             
  1101.                 if (options == kLanguageFunctions) {
  1102.                     
  1103.                     if (token->string[1] == 't') { /* typedef */
  1104.                         typedefLevel = bracketLevel;
  1105.                         typedefStart = token->startLocation;
  1106.                     }
  1107.                     
  1108.                     /* Handle #pragma mark <...> */
  1109.                     
  1110.                     else if (token->string[1] == '#') { /* #pragma */
  1111.                         
  1112.                         int    index = 0;
  1113.                         
  1114.                         while ((token = _languageGetNextToken()) != nil) {
  1115.                             if (token->type != kSymbolWhiteSpace)
  1116.                                 break;
  1117.                         }
  1118.                     
  1119.                         if (token != nil &&
  1120.                             token->type == kSymbolReservedWord &&
  1121.                             token->string[1] == 'm') {
  1122.                             
  1123.                             token->startLocation = globals.position;
  1124.                             
  1125.                             while ((c = languageGetChar(&globals, callbacks)) != -1 &&
  1126.                                     c != 13) {
  1127.                                 
  1128.                                 if (c == ' ' && index == 0) {
  1129.                                 
  1130.                                     token->startLocation = globals.position;
  1131.                                     continue;
  1132.                                 }
  1133.                                 
  1134.                                 if (index < kTokenStringSize)
  1135.                                     token->string[++index] = c;
  1136.                             }
  1137.                         }
  1138.                         
  1139.                         if (index > 0) {
  1140.                         
  1141.                             token->endLocation = globals.position;
  1142.                             token->string[0]   = index;
  1143.                             token->string[++index] = 0;
  1144.                             token->commentLocation = globals.startLastComment;
  1145.  
  1146.                             token->majorType = kFunction;
  1147.                             extTokenReturn(callbacks, token);
  1148.                         }
  1149.                     }
  1150.                 }
  1151.                 else {
  1152.                     token->majorType = kKeyword;
  1153.                 }
  1154.             }
  1155.             else if (type == kSymbolCustomWord) {
  1156.                 token->majorType = kCustomKeyword;
  1157.             }
  1158.             
  1159.             else if (type == kSymbolInclude && options == kLanguageIncludes) {
  1160.        
  1161.                 token->majorType = kFunction;
  1162.                 
  1163.                 extTokenReturn(callbacks, token);
  1164.             }
  1165.             
  1166.             else if (type == kSymbolComment)
  1167.                 token->majorType = kComment;
  1168.             
  1169.             else if (type == kSymbolPreprocessorDirective)
  1170.                 token->majorType = kDirective;
  1171.                 
  1172.             else if (type == kSymbolIdentifier && bracketLevel == 0 && 
  1173.                      functionToken.type == -1) {
  1174.         
  1175.                 saveToken = *token;
  1176.                 
  1177.                 while ((token = _languageGetNextToken()) != nil) {
  1178.                 
  1179.                     if (token->type == kSymbolScope) {
  1180.                         
  1181.                         Int16    x, length = saveToken.string[0];
  1182.                         
  1183.                         if (length < kTokenStringSize)
  1184.                             saveToken.string[++length] = ':';
  1185.                         if (length < kTokenStringSize)
  1186.                             saveToken.string[++length] = ':';
  1187.                         
  1188.                         while ((token = _languageGetNextToken()) != nil) {
  1189.                             
  1190.                             if (token->type == kSymbolWhiteSpace)
  1191.                                 continue;
  1192.                             
  1193.                             if (token->type == kSymbolReservedWord &&
  1194.                                 token->string[1] == 'o' && token->string[2] == 'p') {
  1195.                                 
  1196.                                 /*
  1197.                                  * Get the operator 
  1198.                                  */
  1199.                                  
  1200.                                 tempToken = *token;
  1201.                                 
  1202.                                 while ((token = _languageGetNextToken()) != nil) {
  1203.                                     
  1204.                                     if (token->type == kSymbolWhiteSpace)
  1205.                                         _languageConcatPStrings(tempToken.string, "\p ");
  1206.                                     else if (token->type >= kSymbolLeftParen &&
  1207.                                              token->type <= kSymbolLastCompoundSymbol) {
  1208.                                         token->string[0] = (token->type >= kSymbolFirstCompoundSymbol ? 2 : 1);
  1209.                                         _languageConcatPStrings(tempToken.string, token->string);
  1210.                                         break;
  1211.                                     }
  1212.                                     else
  1213.                                         break;
  1214.                                 }
  1215.                                 
  1216.                                 token = &tempToken;
  1217.                             }
  1218.                             
  1219.                             else if (token->type != kSymbolIdentifier) {
  1220.                                 nextToken = token;
  1221.                                 token      = nil;
  1222.                                 break;
  1223.                             }
  1224.                             
  1225.                             x = token->string[0];
  1226.                             
  1227.                             if (length + x >= kTokenStringSize)
  1228.                                 x = kTokenStringSize - length - 1;
  1229.                             
  1230.                             BlockMove(token->string + 1, 
  1231.                                       saveToken.string + length + 1, x);
  1232.                             length += x;
  1233.                             
  1234.                             break;
  1235.                         }
  1236.                         
  1237.                         saveToken.endLocation = globals.position;
  1238.                         saveToken.string[0]   = length;
  1239.                         saveToken.string[length+1] = 0;
  1240.                         continue;
  1241.                     }
  1242.                     
  1243.                     if (token->type != kSymbolWhiteSpace)
  1244.                         break;
  1245.                 }
  1246.                 
  1247.                 if (token == nil)
  1248.                     break;
  1249.                 
  1250.                 if (token->type == kSymbolLeftParen) {
  1251.                 
  1252.                     functionLevel                 = bracketLevel;
  1253.                     functionToken                 = saveToken;
  1254.                     functionToken.majorType     = kFunction;
  1255.                     
  1256.                     functionToken.commentLocation = globals.startLastComment;
  1257.                     
  1258.                     hadSemicolon  = false;
  1259.                 }
  1260.                 else {
  1261.                     nextToken = token;
  1262.                     continue;
  1263.                 }
  1264.             }
  1265.             
  1266.             else if (type == ';') {
  1267.                 
  1268.                 if (typedefLevel == bracketLevel) {
  1269.                 
  1270.                     saveToken.majorType       = kFunction;
  1271.                     saveToken.commentLocation = typedefStart;
  1272.                     
  1273.                     extTokenReturn(callbacks, &saveToken);
  1274.                     
  1275.                     typedefLevel = -100;
  1276.                 }
  1277.                 else if (bracketLevel == functionLevel) {
  1278.                     hadSemicolon         = true;
  1279.                     functionToken.type     = -1;
  1280.                 }
  1281.             }
  1282.             
  1283.             else if (type == kSymbolLeftBrace)
  1284.                 bracketLevel++;
  1285.             
  1286.             else if (type == kSymbolRightBrace) {
  1287.             
  1288.                 bracketLevel--;
  1289.                 
  1290.                 if (bracketLevel >= 0 && bracketLevel == functionLevel) {
  1291.     
  1292.                     if (!hadSemicolon &&
  1293.                         (options == kLanguageFunctions || options == kLanguageParse)) {
  1294.                         
  1295.                         extTokenReturn(callbacks, &functionToken);
  1296.                     }
  1297.                     
  1298.                     functionLevel         = -1;
  1299.                     functionToken.type     = -1;
  1300.                     continue;
  1301.                 }
  1302.             }
  1303.             
  1304.             /*
  1305.              * Only return a token if it's a interesting token, and
  1306.              * if we are doing a full parse
  1307.              */
  1308.              
  1309.             if (token->majorType >= 0 && options == kLanguageParse)
  1310.                 extTokenReturn(callbacks, token);
  1311.         }
  1312.     }
  1313.     
  1314.     /*
  1315.      * Clean up after ourselves
  1316.      */
  1317.  
  1318.     languageDone(&globals, callbacks);
  1319.     
  1320.     SetA4(saved_a4);
  1321. }
  1322.